package com.ssy.lingxi.order.serviceimpl.platform;

import cn.hutool.core.date.DateUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.ssy.lingxi.common.constant.basic.FundModeEnum;
import com.ssy.lingxi.common.constant.order.OrderTypeEnum;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.order.entity.OrderDO;
import com.ssy.lingxi.order.entity.OrderPaymentDO;
import com.ssy.lingxi.order.model.constant.OrderOuterStatusEnum;
import com.ssy.lingxi.order.model.constant.OrderServiceContants;
import com.ssy.lingxi.order.model.constant.VendorInnerStatusEnum;
import com.ssy.lingxi.order.model.vo.basic.request.OrderIdVO;
import com.ssy.lingxi.order.model.vo.platform.request.PlatformConfirmPayPageVO;
import com.ssy.lingxi.order.model.vo.platform.request.PlatformOrderPageVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformConfirmPayQueryVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformOrderDetailVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformOrderQueryVO;
import com.ssy.lingxi.order.model.vo.platform.response.PlatformPageItemVO;
import com.ssy.lingxi.order.model.vo.vendor.request.ConfirmPayVO;
import com.ssy.lingxi.order.repository.OrderRepository;
import com.ssy.lingxi.order.service.base.IBaseCacheService;
import com.ssy.lingxi.order.service.base.IBaseOrderConsigneeService;
import com.ssy.lingxi.order.service.base.IBaseOrderService;
import com.ssy.lingxi.order.service.platform.IPlatformOrderManageService;
import com.ssy.lingxi.order.service.web.IVendorOrderService;
import com.ssy.lingxi.order.utils.NumberUtil;
import org.apache.poi.ss.usermodel.CellStyle;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 平台后台 - 订单管理相关接口
 * @author 万宁
 * @version 2.0.0
 * @date 2021-07-29
 */
@Service
public class PlatformOrderManageServiceImpl implements IPlatformOrderManageService {
    @Resource
    private IBaseCacheService baseCacheService;

    @Resource
    private IBaseOrderService baseOrderService;

    @Resource
    private IVendorOrderService vendorOrderService;

    @Resource
    private OrderRepository orderRepository;

    @Resource
    private IBaseOrderConsigneeService baseOrderConsigneeService;

    /**
     * （订单查询页面）获取前端页面下拉框列表
     *
     * @param headers HttpHeaders信息
     * @return 查询结果
     */
    @Override
    public Wrapper<PlatformPageItemVO> getPageItems(HttpHeaders headers) {
        baseCacheService.needLoginFromManagePlatform(headers);
        PlatformPageItemVO itemVO = new PlatformPageItemVO();
        itemVO.setOuterStatus(OrderOuterStatusEnum.toDropdownList());
        itemVO.setOrderTypes(baseOrderService.listOrderTypes());
        return Wrapper.success(itemVO);
    }

    /**
     * 分页查询订单列表
     *
     * @param headers HttpHeaders信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<PlatformOrderQueryVO>> pageOrders(HttpHeaders headers, PlatformOrderPageVO pageVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        Pageable pageable = PageRequest.of(pageVO.getCurrent() -1, pageVO.getPageSize(), Sort.by("id").descending());
        Specification<OrderDO> specification = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();

            //订单编号
            if(StringUtils.hasLength(pageVO.getOrderNo())) {
                list.add(criteriaBuilder.like(root.get("orderNo").as(String.class), "%" + pageVO.getOrderNo().trim() + "%"));
            }

            //订单摘要
            if(StringUtils.hasLength(pageVO.getDigest())) {
                list.add(criteriaBuilder.like(root.get("digest").as(String.class), "%" + pageVO.getDigest().trim() + "%"));
            }

            //采购会员名称
            if(StringUtils.hasLength(pageVO.getBuyerMemberName())) {
                list.add(criteriaBuilder.like(root.get("buyerMemberName").as(String.class), "%" + pageVO.getBuyerMemberName().trim() + "%"));
            }

            //供应会员名称
            if(StringUtils.hasLength(pageVO.getVendorMemberName())) {
                list.add(criteriaBuilder.like(root.get("vendorMemberName").as(String.class), "%" + pageVO.getVendorMemberName().trim() + "%"));
            }

            //订单起始时间
            if (StringUtils.hasLength(pageVO.getStartDate())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            }

            //订单结束时间
            if (StringUtils.hasLength(pageVO.getEndDate())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            }

            //订单类型
            if(NumberUtil.notNullOrZero(pageVO.getOrderType())) {
                list.add(criteriaBuilder.equal(root.get("orderType").as(Integer.class), pageVO.getOrderType()));
            }

            //外部状态
            if(NumberUtil.notNullOrZero(pageVO.getOuterStatus())) {
                list.add(criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), pageVO.getOuterStatus()));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<OrderDO> pageList = orderRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(orderDO -> {
            PlatformOrderQueryVO queryVO = new PlatformOrderQueryVO();
            queryVO.setOrderId(orderDO.getId());
            queryVO.setOrderNo(orderDO.getOrderNo());
            queryVO.setCreateTime(orderDO.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            queryVO.setDigest(orderDO.getDigest());
            queryVO.setBuyerMemberName(orderDO.getBuyerMemberName());
            queryVO.setVendorMemberName(orderDO.getVendorMemberName());
            queryVO.setAmount(NumberUtil.formatAmount(orderDO.getTotalAmount()));
            queryVO.setOrderType(orderDO.getOrderType());
            queryVO.setOrderTypeName(OrderTypeEnum.getNameByCode(orderDO.getOrderType()));
            queryVO.setDeliverAddress(baseOrderConsigneeService.orderConsigneeToString(orderDO.getConsignee()));
            queryVO.setOuterStatus(orderDO.getOuterStatus());
            queryVO.setOuterStatusName(OrderOuterStatusEnum.getNameByCode(orderDO.getOuterStatus()));
            return queryVO;
        }).collect(Collectors.toList())));
    }

    /**
     * 查询订单详情
     *
     * @param headers HttpHeaders信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PlatformOrderDetailVO> getOrderDetail(HttpHeaders headers, OrderIdVO idVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        OrderDO order = orderRepository.findById(idVO.getOrderId()).orElse(null);
        if(order == null) {
            return Wrapper.fail(ResponseCode.ORDER_DOES_NOT_EXIST);
        }

        return baseOrderService.getOrderDetail(order);
    }

    /**
     * “待确认支付结果” - 查询订单列表
     *
     * @param headers Http头部信息
     * @param pageVO  接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PageData<PlatformConfirmPayQueryVO>> pageToConfirmPayOrders(HttpHeaders headers, PlatformConfirmPayPageVO pageVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        Pageable pageable = PageRequest.of(pageVO.getCurrent() -1, pageVO.getPageSize(), Sort.by("id").descending());
        Specification<OrderDO> specification = (Specification<OrderDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            //支付记录包含资金归集模式为“平台代收”模式，且外部状态为“待确认支付结果”的
            Join<OrderDO, OrderPaymentDO> paymentJoin = root.join("payments", JoinType.LEFT);
            list.add(criteriaBuilder.and(criteriaBuilder.equal(paymentJoin.get("fundMode").as(Integer.class), FundModeEnum.PLATFORM_EXCHANGE.getCode()), criteriaBuilder.equal(paymentJoin.get("outerStatus").as(Integer.class), OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode())));

            //订单编号
            if(StringUtils.hasLength(pageVO.getOrderNo())) {
                list.add(criteriaBuilder.like(root.get("orderNo").as(String.class), "%" + pageVO.getOrderNo().trim() + "%"));
            }

            //订单摘要
            if(StringUtils.hasLength(pageVO.getDigest())) {
                list.add(criteriaBuilder.like(root.get("digest").as(String.class), "%" + pageVO.getDigest().trim() + "%"));
            }

            //采购会员名称
            if(StringUtils.hasLength(pageVO.getBuyerMemberName())) {
                list.add(criteriaBuilder.like(root.get("buyerMemberName").as(String.class), "%" + pageVO.getBuyerMemberName().trim() + "%"));
            }

            //供应会员名称
            if(StringUtils.hasLength(pageVO.getVendorMemberName())) {
                list.add(criteriaBuilder.like(root.get("vendorMemberName").as(String.class), "%" + pageVO.getVendorMemberName().trim() + "%"));
            }

            //订单起始时间
            if (StringUtils.hasLength(pageVO.getStartDate())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            }

            //订单结束时间
            if (StringUtils.hasLength(pageVO.getEndDate())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            }

            //订单类型
            if(NumberUtil.notNullOrZero(pageVO.getOrderType())) {
                list.add(criteriaBuilder.equal(root.get("orderType").as(Integer.class), pageVO.getOrderType()));
            }

            //供应商内部状态：“待确认支付结果”
            list.add(criteriaBuilder.equal(root.get("vendorInnerStatus").as(Integer.class), VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode()));
            //外部状态：“待确认支付结果”
            list.add(criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode()));

            //去重
            query.distinct(true);

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        Page<OrderDO> pageList = orderRepository.findAll(specification, pageable);
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), pageList.getContent().stream().map(order -> {
            PlatformConfirmPayQueryVO queryVO = new PlatformConfirmPayQueryVO();
            queryVO.setOrderId(order.getId());
            queryVO.setOrderNo(order.getOrderNo());
            queryVO.setCreateTime(order.getCreateTime().format(OrderServiceContants.DEFAULT_TIME_FORMATTER));
            queryVO.setDigest(order.getDigest());
            queryVO.setBuyerMemberName(order.getBuyerMemberName());
            queryVO.setVendorMemberName(order.getVendorMemberName());
            //显示最小的未确认支付的批次
            queryVO.setBatchNo(CollectionUtils.isEmpty(order.getPayments()) ? 0 : order.getPayments().stream().filter(payment -> payment.getFundMode().equals(FundModeEnum.PLATFORM_EXCHANGE.getCode()) && payment.getVendorInnerStatus().equals(VendorInnerStatusEnum.VENDOR_TO_CONFIRM_PAYMENT.getCode()) && payment.getOuterStatus().equals(OrderOuterStatusEnum.TO_CONFIRM_PAYMENT.getCode())).map(OrderPaymentDO::getBatchNo).min(Comparator.comparingInt(Integer::intValue)).orElse(0));
            queryVO.setBatchCount(CollectionUtils.isEmpty(order.getPayments()) ? 0 : order.getPayments().size());
            queryVO.setPaidAmount(NumberUtil.formatAmount(order.getPaidAmount()));

            queryVO.setAmount(NumberUtil.formatAmount(order.getTotalAmount()));
            queryVO.setOrderType(order.getOrderType());
            queryVO.setOrderTypeName(OrderTypeEnum.getNameByCode(order.getOrderType()));
            queryVO.setOuterStatus(order.getOuterStatus());
            queryVO.setOuterStatusName(OrderOuterStatusEnum.getNameByCode(order.getOuterStatus()));
            return queryVO;
        }).collect(Collectors.toList())));
    }

    /**
     * “待确认支付结果” - 查询订单详情
     *
     * @param headers Http头部信息
     * @param idVO    接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<PlatformOrderDetailVO> getToConfirmPayOrderDetails(HttpHeaders headers, OrderIdVO idVO) {
        baseCacheService.needLoginFromManagePlatform(headers);
        OrderDO order = orderRepository.findById(idVO.getOrderId()).orElse(null);
        if(order == null) {
            return Wrapper.fail(ResponseCode.ORDER_DOES_NOT_EXIST);
        }

        return baseOrderService.getOrderDetail(order);
    }

    /**
     * “待确认支付结果” - 确认支付结果
     *
     * @param headers      Http头部信息
     * @param confirmPayVO 接口参数
     * @return 确认结果
     */
    @Override
    public Wrapper<Void> confirmOrderPayment(HttpHeaders headers, ConfirmPayVO confirmPayVO) {
        UserLoginCacheDTO loginUser = baseCacheService.needLoginFromManagePlatform(headers);
        OrderDO order = orderRepository.findById(confirmPayVO.getOrderId()).orElse(null);
        if(order == null) {
            return Wrapper.fail(ResponseCode.ORDER_DOES_NOT_EXIST);
        }

        return vendorOrderService.confirmOrderPayment(order, confirmPayVO, loginUser);
    }

    /**
     * 导出分页查询订单列表
     * @param token 登录token
     * @param pageVO 接口参数
     * @param response 响应体
     */
    @Override
    public void exportOrders(HttpServletResponse response, PlatformOrderPageVO pageVO, String token) {
        baseCacheService.needLoginFromBusinessPlatform(token);
        //构造查询条件
        Specification<OrderDO> specification = (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();

            //订单编号
            if (StringUtils.hasLength(pageVO.getOrderNo())) {
                list.add(criteriaBuilder.like(root.get("orderNo").as(String.class), "%" + pageVO.getOrderNo().trim() + "%"));
            }

            //订单摘要
            if (StringUtils.hasLength(pageVO.getDigest())) {
                list.add(criteriaBuilder.like(root.get("digest").as(String.class), "%" + pageVO.getDigest().trim() + "%"));
            }

            //采购会员名称
            if (StringUtils.hasLength(pageVO.getBuyerMemberName())) {
                list.add(criteriaBuilder.like(root.get("buyerMemberName").as(String.class), "%" + pageVO.getBuyerMemberName().trim() + "%"));
            }

            //供应会员名称
            if (StringUtils.hasLength(pageVO.getVendorMemberName())) {
                list.add(criteriaBuilder.like(root.get("vendorMemberName").as(String.class), "%" + pageVO.getVendorMemberName().trim() + "%"));
            }

            //订单起始时间
            if (StringUtils.hasLength(pageVO.getStartDate())) {
                list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), LocalDateTime.parse(pageVO.getStartDate().concat(" 00:00:00"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            }

            //订单结束时间
            if (StringUtils.hasLength(pageVO.getEndDate())) {
                list.add(criteriaBuilder.lessThanOrEqualTo(root.get("createTime").as(LocalDateTime.class), LocalDateTime.parse(pageVO.getEndDate().concat(" 23:59:59"), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))));
            }

            //订单类型
            if (NumberUtil.notNullOrZero(pageVO.getOrderType())) {
                list.add(criteriaBuilder.equal(root.get("orderType").as(Integer.class), pageVO.getOrderType()));
            }

            //外部状态
            if (NumberUtil.notNullOrZero(pageVO.getOuterStatus())) {
                list.add(criteriaBuilder.equal(root.get("outerStatus").as(Integer.class), pageVO.getOuterStatus()));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };
        //获取销售订单导出数据
        List<OrderDO> orderList = orderRepository.findAll(specification, Sort.by("id").descending());

        List<Map<String, Object>> rows = orderList.stream().map(order -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("订单编号", order.getOrderNo());
            map.put("订单摘要", order.getDigest());
            map.put("采购会员名称", order.getBuyerMemberName());
            map.put("供应会员名称", order.getVendorMemberName());
            map.put("下单时间", order.getCreateTime());
            map.put("订单总额", NumberUtil.formatAmount(order.getTotalAmount()));
            map.put("订单类型名称", OrderTypeEnum.getNameByCode(order.getOrderType()));
            map.put("外部状态名称", OrderOuterStatusEnum.getNameByCode(order.getOuterStatus()));
            return map;
        }).collect(Collectors.toList());

        ExcelWriter writer = ExcelUtil.getBigWriter();
        CellStyle style = writer.getHeadCellStyle();
        style.setWrapText(true);
        writer.write(rows);

        String fileName = "订单-" + DateUtil.date() + ".xls";
        try (ServletOutputStream out = response.getOutputStream()) {
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            writer.flush(out, true);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            writer.close();
        }
    }
}
